/******************************************************************************
 Copyright (c) 2009-2023 Qualcomm Technologies International, Ltd.
 All Rights Reserved.
 Qualcomm Technologies International, Ltd. Confidential and Proprietary.

 REVISION:      $Revision: #9 $
******************************************************************************/

#include "csr_synergy.h"
#include "csr_bt_cm_main.h"
#include "csr_bt_cm_l2cap.h"
#include "csr_bt_cm_lib.h"
#include "csr_bt_cm_private_lib.h"
#include "csr_bt_cm_rfc.h"
#include "csr_bt_cm_dm.h"
#include "csr_bt_cm_util.h"

#ifndef EXCLUDE_CSR_BT_BNEP_MODULE
#include "csr_bt_cm_bnep.h"
#endif

#ifndef EXCLUDE_CSR_BT_CM_BCCMD_FEATURE
#include "csr_bt_cm_bccmd.h"
#endif

#ifndef EXCLUDE_CSR_BT_SC_MODULE
#include "csr_bt_sc_private_lib.h"
#endif

#define WRITE_SCAN_ENABLE_MAX_RETRY 10

#if defined(CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE) && defined(CSR_BT_INSTALL_CM_WRITE_COD)
#define CSR_BT_CM_COD_STATE_SET(_dmVar, _state)     ((_dmVar).writingCod = (_state))
#define CSR_BT_CM_COD_STATE_IS_SET(_dmVar)          ((_dmVar).writingCod != FALSE)
#else
#define CSR_BT_CM_COD_STATE_SET(_dmVar, _state)
#define CSR_BT_CM_COD_STATE_IS_SET(_dmVar)          TRUE
#endif

#ifdef CSR_BT_INSTALL_CM_READ_COD
void CsrBtCmReadCodReqHandler(cmInstanceData_t *cmData)
{
    CsrBtCmReadCodReq  *prim;

    prim = (CsrBtCmReadCodReq *) cmData->recvMsgP;

    cmData->dmVar.appHandle = prim->appHandle;
    dm_hci_read_class_of_device(NULL);
}

void CsrBtCmDmHciReadClassOfDeviceCompleteHandler(cmInstanceData_t *cmData)
{ /* Read class of device complete */
    DM_HCI_READ_CLASS_OF_DEVICE_CFM_T * dmPrim = (DM_HCI_READ_CLASS_OF_DEVICE_CFM_T *) cmData->recvMsgP;
    CsrBtCmReadCodCfm                 * cmPrim = (CsrBtCmReadCodCfm *)CsrPmemAlloc(sizeof(CsrBtCmReadCodCfm));

    cmPrim->type            = CSR_BT_CM_READ_COD_CFM;
    cmPrim->classOfDevice   = dmPrim->dev_class;

    if(dmPrim->status == HCI_SUCCESS)
    {
        cmPrim->resultCode      = CSR_BT_RESULT_CODE_CM_SUCCESS;
        cmPrim->resultSupplier  = CSR_BT_SUPPLIER_CM;
    }
    else
    {
        cmPrim->resultCode      = (CsrBtResultCode) dmPrim->status;
        cmPrim->resultSupplier  = CSR_BT_SUPPLIER_HCI;
    }
    CsrBtCmPutMessage(cmData->dmVar.appHandle, cmPrim);
    CsrBtCmDmLocalQueueHandler();
}
#endif
#ifndef EXCLUDE_CSR_BT_RFC_MODULE
void CsrBtCmRfcCancelConnectAcceptReqHandler(cmInstanceData_t *cmData)
{
    CsrBtCmCancelAcceptConnectReq * cmPrim = (CsrBtCmCancelAcceptConnectReq *) cmData->recvMsgP;
    cmConnIdServerContextType  serverInst       = CsrBtCmReturnConnIdServerContextStruct(CSR_BT_CONN_ID_CANCELLED, cmPrim->serverChannel, cmPrim->context);
    cmRfcConnElement * theElement  = CM_FIND_RFC_ELEMENT(CsrBtCmRfcFindRfcConnElementFromConnIdServerContext, &(serverInst));

    if(theElement)
    { /* The device is connectable. Remove COD and cancel the service */
        cmRfcConnInstType *theLogicalLink   = theElement->cmRfcConnInst;
        cmData->rfcVar.activeElemId         = theElement->elementId;
        theLogicalLink->btConnId            = CSR_BT_CONN_ID_INVALID;
        CSR_BT_CM_STATE_CHANGE(theLogicalLink->state,
                               CSR_BT_CM_RFC_STATE_CANCEL_CONNECTABLE);
        CmRfcRemoteConnectionStateHandler(cmData, theElement);
    }
    else
    { /* The CM can not cancel the service.Restore the RFC queue. */
        
        CsrBtCmServiceManagerLocalQueueHandler(cmData);
    }
}
#endif /* EXCLUDE_CSR_BT_RFC_MODULE */

#ifdef CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE
#ifndef EXCLUDE_CSR_BT_BNEP_MODULE
static void cmDmWriteScanEnableBnepCompleteHandler(cmInstanceData_t *cmData,
                                                   CsrBtResultCode resultCode,
                                                   CsrBtSupplier resultSupplier)
{
    bnepTable * bnepLink = cmData->bnepVar.indexPtr;

    switch(bnepLink->state)
    {
        case CSR_BT_CM_BNEP_STATE_CONNECT_ACCEPT:
            { /* The CM has just try to make a application connectable.
                 Restore the local DM queue */
                CsrBtCmBnepConnectAcceptCfmMsgSend(cmData, cmData->bnepVar.appHandle, resultCode, resultSupplier);

                if (resultCode == CSR_BT_RESULT_CODE_CM_SUCCESS && resultSupplier == CSR_BT_SUPPLIER_CM)
                {
                    CSR_BT_CM_STATE_CHANGE(bnepLink->state,
                                           CSR_BT_CM_BNEP_STATE_IDLE);
                }
                else
                {
                    CsrBtCmBnepClearBnepTableIndex(bnepLink);
                }
                cmData->bnepVar.connectTypeInProgress = NO_CONNECT;
                CsrBtCmDmLocalQueueHandler();
                break;
            }
        case CSR_BT_CM_BNEP_STATE_CONNECT_ACCEPT_FINAL:
            {
                CsrBtCmBnepCancelConnectAcceptCfmMsgSend(cmData->bnepVar.appHandle,
                                                         CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);
                CsrBtCmDmLocalQueueHandler();
                break;
            }
        case CSR_BT_CM_BNEP_STATE_CANCEL_CONNECT_ACCEPT:
            { /* The connect accept service is cancel. Send CM_BNEP_CANCEL_ACCEPT_CONNECT_CFM
                 to the application and restore the local service manager and the local DM
                 queue. */
                CsrBtCmBnepCancelConnectAcceptCfmMsgSend(cmData->bnepVar.appHandle,
                                                         CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);
                CsrBtCmBnepClearBnepTableIndex(bnepLink);
                CsrBtCmDmLocalQueueHandler();
                CsrBtCmServiceManagerLocalQueueHandler(cmData);
                break;
            }
        default :
            {
                CsrBtCmServiceManagerLocalQueueHandler(cmData);
                CsrBtCmDmLocalQueueHandler();
                break;
            }
    }
}
#endif /* EXCLUDE_CSR_BT_BNEP_MODULE */
#endif /* CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE */

static void csrBtCmWriteScanEnableCfmMsgSend(CsrSchedQid appHandle, CsrBtResultCode resultCode, CsrBtSupplier resultSupplier)
{
    CsrBtCmWriteScanEnableCfm *msg = (CsrBtCmWriteScanEnableCfm *)CsrPmemAlloc(sizeof(CsrBtCmWriteScanEnableCfm));
    msg->type                      = CSR_BT_CM_WRITE_SCAN_ENABLE_CFM;
    msg->resultCode                = resultCode;
    msg->resultSupplier            = resultSupplier;
    CsrBtCmPutMessage(appHandle, msg);
}

static CsrBool csrBtCmWriteScanEnableCmCompleteHandler(cmInstanceData_t *cmData,
                                                       CsrBtResultCode resultCode,
                                                       CsrBtSupplier resultSupplier)
{
    CsrBool restoreDmQueue = TRUE;
    if (resultCode == CSR_BT_RESULT_CODE_CM_SUCCESS && resultSupplier == CSR_BT_SUPPLIER_CM)
    {
        if (cmData->globalState == CSR_BT_CM_STATE_NOT_READY)
        {
            restoreDmQueue = FALSE;
        }
        else
        {
            csrBtCmWriteScanEnableCfmMsgSend(cmData->dmVar.appHandle, resultCode, resultSupplier);
        }
    }
    else if (cmData->globalState != CSR_BT_CM_STATE_NOT_READY)
    {
        if (cmData->dmVar.retryCounter++ < WRITE_SCAN_ENABLE_MAX_RETRY)
        {
            /* Fail try again */
            CsrUint8 mode = returnConnectAbleParameters(cmData);
            restoreDmQueue = FALSE;
            dm_hci_write_scan_enable(mode, NULL);
        }
        else
        {
            csrBtCmWriteScanEnableCfmMsgSend(cmData->dmVar.appHandle, resultCode, resultSupplier);
        }
    }

    return restoreDmQueue;
}

#ifdef CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE
#ifndef EXCLUDE_CSR_BT_RFC_MODULE
static void cmAcceptConnectWithTimeOut(CsrUint8 theIndex, cmInstanceData_t *cmData)
{
    cmRfcConnElement * theElement = CM_FIND_RFC_ELEMENT(CsrBtCmRfcFindRfcConnElementFromIndex, &(theIndex));

    if (theElement)
    {
        /* Remove the COD. Check if the Host still need to be connectable and
           send CSR_BT_CM_CONNECT_ACCEPT_CFM with timeout to the application */
        cmRfcConnInstType *theLogicalLink = theElement->cmRfcConnInst;
        CsrBtCmAcceptConnectTimeout *prim = (CsrBtCmAcceptConnectTimeout*) CsrPmemAlloc(sizeof(CsrBtCmAcceptConnectTimeout));

        theLogicalLink->timerId = CSR_SCHED_TID_INVALID;

        prim->type = CSR_BT_CM_ACCEPT_CONNECT_TIMEOUT;
        prim->serverChannel = theLogicalLink->serverChannel;
        CSR_BT_CM_STATE_CHANGE(theLogicalLink->state,
                               CSR_BT_CM_RFC_STATE_CANCEL_TIMER);

        cmData->recvMsgP = prim;
        CsrBtCmServiceManagerProvider(cmData);

        SynergyMessageFree(CSR_BT_CM_PRIM, cmData->recvMsgP);
        cmData->recvMsgP = NULL;
    }
    else
    {
        CsrBtCmGeneralException(CSR_BT_CM_PRIM,
                                CSR_BT_CM_ACCEPT_CONNECT_TIMEOUT,
                                0,
                                "Did not find any cmRfcConnElement");
    }
}

#define CSR_BT_MAX_TIME     (2000000000)

static void cmStartSuperVisionTimer(cmInstanceData_t *cmData, cmRfcConnInstType * theLink, uuid16_t theTime, CsrUint8 theIndex)
{/* Start supervision timer  and initialise the instance variables,
    if not set to 0, which is infinit */
    if(theTime != CSR_BT_INFINITE_TIME)
    {
        if(theTime > (CSR_BT_MAX_TIME / CSR_BT_MICROSEC2SEC))
        {
            theTime = (CSR_BT_MAX_TIME / CSR_BT_MICROSEC2SEC);
        }
        theLink->timerId   = CsrSchedTimerSet(theTime*CSR_BT_MICROSEC2SEC,
                                              (void (*) (CsrUint16, void *)) cmAcceptConnectWithTimeOut,
                                              (CsrUint16) theIndex,
                                              (void *) cmData);
    }
}

static void cmDmConnectableHandler(cmInstanceData_t    *cmData,
                                 cmRfcConnElement    *theElement,
                                 CsrUint8             index,
                                 CsrBtResultCode     resultCode,
                                 CsrBtSupplier resultSupplier)
{
    if(resultCode == CSR_BT_RESULT_CODE_CM_SUCCESS && resultSupplier == CSR_BT_SUPPLIER_CM)
    { /* The hostcontroller is connectable */
        cmRfcConnInstType *theLogicalLink = theElement->cmRfcConnInst;

        CSR_BT_CM_STATE_CHANGE(theLogicalLink->state, CSR_BT_CM_RFC_STATE_IDLE);
        cmStartSuperVisionTimer(cmData, theLogicalLink, cmData->rfcVar.connectAcceptTimeOut, index);
    }
    else
    { /* The hostcontroller could not enter scan mode. Build and send
         CSR_BT_CM_CONNECT_ACCEPT_CFM to the application. Restore the RFC
         the queue */
        CsrBtCmConnectAcceptCfmMsgSend(cmData, theElement, resultCode, resultSupplier);
    }
}
static CsrBool cmDmWriteScanEnableRfcCompleteHandler(cmInstanceData_t *cmData,
                                                     CsrBtResultCode resultCode,
                                                     CsrBtSupplier resultSupplier)
{
    cmRfcConnElement *rfcConnElement = CM_RFC_ELEMENT_ACTIVE(cmData);
    CsrBool restoreQueue = TRUE;

    if (rfcConnElement && rfcConnElement->cmRfcConnInst)
    {
        switch (rfcConnElement->cmRfcConnInst->state)
        {
            case CSR_BT_CM_RFC_STATE_CONNECTABLE:
            {
                /* The CM has just make a application connectable. Start supervision
                   timer and restore RFC queue */
                cmDmConnectableHandler(cmData,
                                       rfcConnElement,
                                       rfcConnElement->elementId,
                                       resultCode,
                                       resultSupplier);
                break;
            }

            case CSR_BT_CM_RFC_STATE_CONNECT_ACCEPT:
            case CSR_BT_CM_RFC_STATE_CONNECT_ACCEPT_FINAL:
            {
                cmRfcConnInstType *theLogicalLink = rfcConnElement->cmRfcConnInst;

                if (cmData->smVar.arg.result.code == CSR_BT_RESULT_CODE_CM_SUCCESS &&
                    cmData->smVar.arg.result.supplier == CSR_BT_SUPPLIER_CM)
                { /* A new RFCOMM connection have just been establish with SUCCESS.
                     Write lp settings and inform the application */
#ifdef CSR_BT_INSTALL_CM_INTERNAL_LP_CONTROL
                    CsrUint8 numOfConnection = CsrBtCmReturnNumOfConnectionsToPeerDevice(cmData,
                                                                                         theLogicalLink->deviceAddr);

                    if (numOfConnection == 0)
                    { /* There is no other connection attach to the device address.
                         Ensure that SNIFF mode is supported */
                        CsrBtCmDmWriteLpSettingsAllMsgSend(cmData, theLogicalLink->deviceAddr, KEEP_CURRENT_PLAYER);
                        /* Both DM and SM queue needs to be unlocked by respective LP settings handler. */
                        restoreQueue = FALSE;
                    }
                    else
#endif /* CSR_BT_INSTALL_CM_INTERNAL_LP_CONTROL */
                    { /* Currently there is at least one more connection attach to this
                         device address. The rfc connection has been accepted with with success.
                         Inform the application, and restore the local service manager
                         and DM queue */
                        CsrBtCmConnectAcceptCfmMsgSend(cmData, rfcConnElement, CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);
#ifndef CSR_BT_INSTALL_LP_POWER_TABLE
                        {
                            aclTable *aclConnectionElement;

                            if (returnAclConnectionElement(cmData, theLogicalLink->deviceAddr, &aclConnectionElement) != CM_ERROR &&
                                aclConnectionElement->mode != CSR_BT_ACTIVE_MODE)
                            {
                                if (!aclConnectionElement->appControlsLowPower)
                                {
                                    CsrBtCmRfcModeChangeReqSend(theLogicalLink->btConnId, CSR_BT_ACTIVE_MODE);
                                }
                                else
                                {
                                    /* The application is controlling low power. Inform the profile about current mode */
                                    CsrBtCmRfcModeChangeIndMsgSend(theLogicalLink,
                                                                   aclConnectionElement->interval,
                                                                   aclConnectionElement->mode,
                                                                   CSR_BT_RESULT_CODE_CM_SUCCESS,
                                                                   CSR_BT_SUPPLIER_CM);
                                }
                            }
                        }
#endif /* !CSR_BT_INSTALL_LP_POWER_TABLE */
                    }
                }
                break;
            }

            case CSR_BT_CM_RFC_STATE_CANCEL_TIMER:
            case CSR_BT_CM_RFC_STATE_CANCEL_CONNECTABLE:
            {
                /* Since these states are independent of auto scan procedure, these are handled
                 * immediately in CmRfcRemoteConnectionStateHandler. Unlocks for SM and DM are
                 * handled here in order to maintain the smVar.activePlayer value.*/
                break;
            }

            default:
                break;
        }
    }
    return restoreQueue;
}
#endif /* !EXCLUDE_CSR_BT_RFC_MODULE */

#ifndef EXCLUDE_CSR_BT_L2CA_MODULE
static CsrBool cmDmWriteScanEnableL2caCompleteHandler(cmInstanceData_t *cmData,
                                                      CsrBtResultCode resultCode,
                                                      CsrBtSupplier resultSupplier)
{
    cmL2caConnElement *l2caConnElement = CM_L2CA_ELEMENT_ACTIVE(cmData);
    CsrBool restoreQueue = TRUE;

    if (l2caConnElement && l2caConnElement->cmL2caConnInst)
    {
        switch (l2caConnElement->cmL2caConnInst->state)
        {
            case CSR_BT_CM_L2CAP_STATE_CONNECTABLE:
            {
                if (resultCode == CSR_BT_RESULT_CODE_CM_SUCCESS &&
                    resultSupplier == CSR_BT_SUPPLIER_CM)
                {/* The device is now connectable. Restore the local service manager
                    queue */
                    CSR_BT_CM_STATE_CHANGE(l2caConnElement->cmL2caConnInst->state,
                                           CSR_BT_CM_L2CAP_STATE_IDLE);
                }
                else
                { /* The attempt to make the device connectable fails. Inform the
                     application, restore the local l2cap queue, and clean up
                     the l2cap connection table */
                    CsrBtCmL2caConnectAcceptCfmHandler(cmData, l2caConnElement, resultCode, resultSupplier);
                }
                break;
            }

            case CSR_BT_CM_L2CAP_STATE_CONNECT_ACCEPT_FINAL:
            {/* The l2cap connection is now establish with with success. Inform the
                application, and restore the  local service manager and DM queue */
                cmL2caConnInstType *l2capLink = l2caConnElement->cmL2caConnInst;

#ifdef CSR_BT_INSTALL_CM_INTERNAL_LP_CONTROL
                CsrUint8 numOfConnection = CsrBtCmReturnNumOfConnectionsToPeerDevice(cmData, l2capLink->deviceAddr);

                if (numOfConnection == 0)
                { /* There is no other connection attach to the device address.
                     Ensure that SNIFF mode is supported */
                    CsrBtCmDmWriteLpSettingsAllMsgSend(cmData, l2capLink->deviceAddr, KEEP_CURRENT_PLAYER);
                    /* Both DM and SM queue needs to be unlocked by respective LP settings handler. */
                    restoreQueue = FALSE;
                }
                else
#endif /* CSR_BT_INSTALL_CM_INTERNAL_LP_CONTROL */
                { /* Currently there is at least one more connection attach to the
                     device address. The l2cap connection has been accepted with with success.
                     Inform the application, and restore the local service manager and
                     DM queue */
                    CSR_BT_CM_STATE_CHANGE(l2capLink->state,CSR_BT_CM_L2CAP_STATE_CONNECTED);

                    CsrBtCmL2caConnectAcceptCfmHandler(cmData, l2caConnElement,
                                                       CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);

#ifndef CSR_BT_INSTALL_LP_POWER_TABLE
                    {
                        aclTable *aclConnectionElement;

                        if (returnAclConnectionElement(cmData, l2capLink->deviceAddr, &aclConnectionElement) != CM_ERROR &&
                            aclConnectionElement->mode != CSR_BT_ACTIVE_MODE)
                        {
                            if (!aclConnectionElement->appControlsLowPower)
                            {
                                CsrBtCml2caModeChangeReqSend(l2capLink->btConnId, CSR_BT_ACTIVE_MODE);
                            }
                            else
                            {
                                /* The application is controlling low power. Inform the profile about current mode */
                                CsrBtCmL2caModeChangeIndMsgSend(l2capLink,
                                                                aclConnectionElement->interval,
                                                                aclConnectionElement->mode,
                                                                CSR_BT_RESULT_CODE_CM_SUCCESS,
                                                                CSR_BT_SUPPLIER_CM);
                            }
                        }
                    }
#endif /* !CSR_BT_INSTALL_LP_POWER_TABLE */
                }
                break;
            }

            case CSR_BT_CM_L2CAP_STATE_SAVE_DISCONNECT:
            case CSR_BT_CM_L2CAP_STATE_CANCEL_CONNECTABLE:
            {
                /* Since these states are independent of auto scan procedure, these are handled
                 * immediately in CmL2caRemoteConnectionStateHandler. Unlocks for SM and DM are
                 * handled here in order to maintain the smVar.activePlayer value.*/
                break;
            }

            default:
                break;
        }
    }
    return restoreQueue;
}
#endif /* !EXCLUDE_CSR_BT_L2CA_MODULE */
#endif /* CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE */

void CsrBtCmWriteScanEnableCompleteSwitch(cmInstanceData_t *cmData, CsrBtResultCode resultCode, CsrBtSupplier resultSupplier)
{
    CsrBool restoreDmQueue = FALSE, restoreSmQueue = FALSE;

#ifdef CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE
    switch (cmData->smVar.activePlayer)
    {
#ifndef EXCLUDE_CSR_BT_RFC_MODULE
        case RFC_PLAYER:
        {
            /* In case if the handler continues to complete further procedures like e.g. link policy,
             * both SM and DM queues needs to be locked. */
            restoreSmQueue = cmDmWriteScanEnableRfcCompleteHandler(cmData,
                                                                   resultCode,
                                                                   resultSupplier);
            restoreDmQueue = restoreSmQueue;
            break;
        }
#endif /* EXCLUDE_CSR_BT_RFC_MODULE */

#ifndef EXCLUDE_CSR_BT_L2CA_MODULE
        case L2CAP_PLAYER:
        {
            /* In case if the handler continues to complete further procedures like e.g. link policy,
             * both SM and DM queues needs to be locked. */
            restoreSmQueue = cmDmWriteScanEnableL2caCompleteHandler(cmData,
                                                                    resultCode,
                                                                    resultSupplier);
            restoreDmQueue = restoreSmQueue;
            break;
        }
#endif /* EXCLUDE_CSR_BT_L2CA_MODULE */

#ifndef EXCLUDE_CSR_BT_BNEP_MODULE
        case BNEP_PLAYER:
        {
            /* Freeing of DM and SM queue is left to this function call. */
            cmDmWriteScanEnableBnepCompleteHandler(cmData,
                                                   resultCode,
                                                   resultSupplier);
            break;
        }
#endif /* EXCLUDE_CSR_BT_BNEP_MODULE*/

        case CM_PLAYER:
        {
            restoreDmQueue = csrBtCmWriteScanEnableCmCompleteHandler(cmData,
                                                                     resultCode,
                                                                     resultSupplier);
            break;
        }

        default:
        {
            /* Ignore the message as it doesn't belong to interested player. */
            break;
        }
    }
#else /* CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE */
    restoreDmQueue = csrBtCmWriteScanEnableCmCompleteHandler(cmData,
                                                             resultCode,
                                                             resultSupplier);
#endif /* !CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE */

    if (restoreDmQueue)
    {
        CsrBtCmDmLocalQueueHandler();
    }

    if (restoreSmQueue)
    {
        /* In case of L2CAP and RFC, the SM queue will remain lock in order to
         * maintain the integrity of smVar.activePlayer, hence it needs to be unlocked here. */
        CsrBtCmServiceManagerLocalQueueHandler(cmData);
    }
}

void CsrBtCmDmHciWriteScanEnableCompleteHandler(cmInstanceData_t *cmData)
{
    DM_HCI_WRITE_SCAN_ENABLE_CFM_T    *dmPrim;

    dmPrim = (DM_HCI_WRITE_SCAN_ENABLE_CFM_T *)cmData->recvMsgP;

    if(dmPrim->status == HCI_SUCCESS)
    {
        cmData->dmVar.currentChipScanMode = cmData->dmVar.pendingChipScanMode;
    }

#ifdef CSR_BT_INSTALL_CM_DUT_MODE
    if (cmData->dmVar.deviceUnderTest)
    {
        if (dmPrim->status == HCI_SUCCESS)
        {
            dm_hci_enable_device_ut_mode(NULL);
        }
        else
        {
            CsrBtCmSendDeviceUnderTestComplete(cmData->dmVar.appHandle, dmPrim->status, 2);
        }
    }
    else
#endif
    {
        if (cmData->globalState == CSR_BT_CM_STATE_NOT_READY)
        {
            /* Currently we are in initialization phase, handle this using init sequence handler. */
            CmInitSequenceHandler(cmData,
                                  CM_INIT_SEQ_WRITE_SCAN_ENABLE_CFM,
                                  (CsrBtResultCode) dmPrim->status,
                                  CSR_BT_SUPPLIER_HCI);
        }

        if (dmPrim->status == HCI_SUCCESS)
        {
            CsrBtCmWriteScanEnableCompleteSwitch(cmData, CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);
        }
        else
        {
            CsrBtCmWriteScanEnableCompleteSwitch(cmData, (CsrBtResultCode) dmPrim->status, CSR_BT_SUPPLIER_HCI);
        }
    }
}

#ifdef CSR_BT_INSTALL_CM_WRITE_COD
static void csrBtCmWriteClassOfDeviceCfmMsgSend(CsrSchedQid appHandle, CsrBtResultCode resultCode, CsrBtSupplier resultSupplier)
{
    CsrBtCmWriteCodCfm *msg = (CsrBtCmWriteCodCfm *)CsrPmemAlloc(sizeof(CsrBtCmWriteCodCfm));
    msg->type               = CSR_BT_CM_WRITE_COD_CFM;
    msg->resultCode         = resultCode;
    msg->resultSupplier     = resultSupplier;
    CsrBtCmPutMessage(appHandle, msg);
}

void CsrBtCmWriteCodReqHandler(cmInstanceData_t *cmData)
{ /* Find the actual Class Of Device and send the command to the hostcontroller */
    CsrUint24 classOfDevice;
    CsrBtCmWriteCodReq *cmPrim = (CsrBtCmWriteCodReq*) cmData->recvMsgP;

    CSR_BT_CM_COD_STATE_SET(cmData->dmVar, TRUE);
    cmData->dmVar.appHandle = cmPrim->appHandle;

    if (cmPrim->updateFlags & CSR_BT_CM_WRITE_COD_UPDATE_FLAG_MAJOR_MINOR_CLASS)
    {
        cmData->dmVar.majorCod = cmPrim->majorClassOfDevice;
        cmData->dmVar.minorCod = cmPrim->minorClassOfDevice;
    }
    if (cmPrim->updateFlags & CSR_BT_CM_WRITE_COD_UPDATE_FLAG_SERVICE_CLASS)
    {
        cmData->dmVar.serviceCod = cmPrim->serviceClassOfDevice;
    }

    classOfDevice = CsrBtCmReturnClassOfdevice(cmData);

    if (classOfDevice != cmData->dmVar.codWrittenToChip)
    {
        cmData->dmVar.pendingCod = classOfDevice;
        dm_hci_write_class_of_device(classOfDevice, NULL);
    }
    else
    {
        CSR_BT_CM_COD_STATE_SET(cmData->dmVar, FALSE);
        csrBtCmWriteClassOfDeviceCfmMsgSend(cmData->dmVar.appHandle,
                                            CSR_BT_RESULT_CODE_CM_SUCCESS,
                                            CSR_BT_SUPPLIER_CM);
        CsrBtCmDmLocalQueueHandler();
    }
}
#endif /* CSR_BT_INSTALL_CM_WRITE_COD */

void CsrBtCmDmHciWriteClassOfDeviceCompleteHandler(cmInstanceData_t *cmData)
{ /* Write class of device complete */
#if defined(CSR_BT_INSTALL_CM_WRITE_COD) || defined(CSR_BT_INSTALL_CM_PRI_IAC)
    CsrBtResultCode                    resultCode;
    CsrBtSupplier                resultSupplier;
    DM_HCI_WRITE_CLASS_OF_DEVICE_CFM_T *dmPrim = (DM_HCI_WRITE_CLASS_OF_DEVICE_CFM_T *) cmData->recvMsgP;

    if(dmPrim->status == HCI_SUCCESS)
    {
        cmData->dmVar.codWrittenToChip = cmData->dmVar.pendingCod;
        resultCode                     = CSR_BT_RESULT_CODE_CM_SUCCESS;
        resultSupplier                 = CSR_BT_SUPPLIER_CM;
    }
    else
    {
        resultCode                     = (CsrBtResultCode) dmPrim->status;
        resultSupplier                 = CSR_BT_SUPPLIER_HCI;
    }
#endif /* defined(CSR_BT_INSTALL_CM_WRITE_COD) || defined(CSR_BT_INSTALL_CM_PRI_IAC) */

#ifdef CSR_BT_INSTALL_CM_WRITE_COD
    if (CSR_BT_CM_COD_STATE_IS_SET(cmData->dmVar) &&
        cmData->globalState == CSR_BT_CM_STATE_IDLE)
    {
        CSR_BT_CM_COD_STATE_SET(cmData->dmVar, FALSE);
        csrBtCmWriteClassOfDeviceCfmMsgSend(cmData->dmVar.appHandle, resultCode, resultSupplier);
        CsrBtCmDmLocalQueueHandler();
    }
    else
#endif /* CSR_BT_INSTALL_CM_WRITE_COD */
    {
        if (cmData->globalState == CSR_BT_CM_STATE_NOT_READY)
        {
            CmInitSequenceHandler(cmData,
                                  CM_INIT_SEQ_WRITE_COD_CFM,
                                  (CsrBtResultCode) dmPrim->status,
                                  CSR_BT_SUPPLIER_HCI);
        }
    }
}

#ifdef CSR_BT_INSTALL_CM_READ_SCAN_EANBLE
void CsrBtCmDmHciReadScanEnableCompleteHandler(cmInstanceData_t *cmData)
{
    CsrBtCmReadScanEnableCfm * cmPrim = (CsrBtCmReadScanEnableCfm *) CsrPmemAlloc(sizeof(CsrBtCmReadScanEnableCfm));
    DM_HCI_READ_SCAN_ENABLE_CFM_T * dmPrim = (DM_HCI_READ_SCAN_ENABLE_CFM_T *) cmData->recvMsgP;

    cmPrim->type       = CSR_BT_CM_READ_SCAN_ENABLE_CFM;
    cmPrim->scanEnable = dmPrim->scan_enable;

    if (dmPrim->status == HCI_SUCCESS)
    {
        cmPrim->resultCode      = CSR_BT_RESULT_CODE_CM_SUCCESS;
        cmPrim->resultSupplier  = CSR_BT_SUPPLIER_CM;
    }
    else
    {
        cmPrim->resultCode      = (CsrBtResultCode) dmPrim->status;
        cmPrim->resultSupplier  = CSR_BT_SUPPLIER_HCI;
    }

    CsrBtCmPutMessage(cmData->dmVar.appHandle, cmPrim);
    CsrBtCmDmLocalQueueHandler();
}

void CsrBtCmReadScanEnableReqHandler(cmInstanceData_t *cmData)
{
    CsrBtCmReadScanEnableReq *cmPrim = (CsrBtCmReadScanEnableReq*) cmData->recvMsgP;

    cmData->dmVar.appHandle = cmPrim->appHandle;
    dm_hci_read_scan_enable(NULL);
}
#endif /* CSR_BT_INSTALL_CM_READ_SCAN_EANBLE */

void CsrBtCmWriteScanEnableReqHandler(cmInstanceData_t *cmData)
{
    CsrUint8 mode;
    CsrBtCmWriteScanEnableReq *cmPrim = (CsrBtCmWriteScanEnableReq*) cmData->recvMsgP;

    cmData->dmVar.appHandle = cmPrim->appHandle;
    cmData->dmVar.disableInquiryScan = cmPrim->disableInquiryScan;
    cmData->dmVar.disablePageScan = cmPrim->disablePageScan;
    cmData->dmVar.retryCounter = 0;
#ifdef CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE
    cmData->smVar.activePlayer = CM_PLAYER;
#endif
    mode = returnConnectAbleParameters(cmData);

    if (mode != cmData->dmVar.currentChipScanMode)
    {
        cmData->dmVar.pendingChipScanMode = mode;
        dm_hci_write_scan_enable(mode, NULL);
    }
    else
    {
        CsrBtCmWriteScanEnableCompleteSwitch(cmData,
                                             CSR_BT_RESULT_CODE_CM_SUCCESS,
                                             CSR_BT_SUPPLIER_CM);
    }
}

#ifdef CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE
void CmDmWriteAutoScanEnable(CsrUint8 thePlayer)
{
    CmWriteAutoScanEnableReq  *prim;

    prim = (CmWriteAutoScanEnableReq *) CsrPmemAlloc(sizeof(CmWriteAutoScanEnableReq));
    prim->type            = CSR_BT_CM_WRITE_AUTO_SCAN_ENABLE_REQ;
    prim->activePlayer    = thePlayer;
    CsrBtCmPutMessage(CSR_BT_CM_IFACEQUEUE, prim);
}

void CmWriteAutoScanEnableReqHandler(cmInstanceData_t *cmData)
{
    CsrUint8 mode;
    CsrUint24 classOfDevice;
    CmWriteAutoScanEnableReq *cmPrim;

    cmPrim = (CmWriteAutoScanEnableReq *) cmData->recvMsgP;
    cmData->smVar.activePlayer = cmPrim->activePlayer;
    mode = returnConnectAbleParameters(cmData);

    classOfDevice = CsrBtCmReturnClassOfdevice(cmData);

    if (classOfDevice != cmData->dmVar.codWrittenToChip)
    {
        /* We don't need to wait for the result of class of device, locks will be freed once the scan procedure gets over. */
        cmData->dmVar.pendingCod = classOfDevice;
        dm_hci_write_class_of_device(classOfDevice, NULL);
    }

    if (mode != cmData->dmVar.currentChipScanMode)
    {
        cmData->dmVar.pendingChipScanMode = mode;
        dm_hci_write_scan_enable(mode, NULL);
    }
    else
    {
        CsrBtCmWriteScanEnableCompleteSwitch(cmData, CSR_BT_RESULT_CODE_CM_SUCCESS, CSR_BT_SUPPLIER_CM);
    }
}
#endif /* CSR_BT_INSTALL_CM_AUTO_SCAN_ENABLE */

